package com.airbnb.lottie.parser;

import com.airbnb.lottie.parser.moshi.JsonReader;
import com.airbnb.lottie.model.animatable.AnimatableFloatValue;
import com.airbnb.lottie.LottieComposition;
import com.airbnb.lottie.model.animatable.AnimatableIntegerValue;
import com.airbnb.lottie.model.animatable.AnimatablePathValue;
import com.airbnb.lottie.model.animatable.AnimatableScaleValue;
import com.airbnb.lottie.model.animatable.AnimatableSplitDimensionPathValue;
import com.airbnb.lottie.model.animatable.AnimatableTransform;
import com.airbnb.lottie.model.animatable.AnimatableValue;
import com.airbnb.lottie.value.Keyframe;
import ohos.agp.utils.Point;

import java.io.IOException;

public class AnimatableTransformParser {

    private AnimatableTransformParser() {
    }

    private static final JsonReader.Options NAMES = JsonReader.Options.of("a", "p", "s", "rz", "r", "o", "so", "eo", "sk",
        "sa");

    private static final JsonReader.Options ANIMATABLE_NAMES = JsonReader.Options.of("k");

    public static AnimatableTransform parse(JsonReader reader, LottieComposition composition) throws IOException {
        AnimatablePathValue anchorPoint = null;
        AnimatableValue<Point, Point> position = null;
        AnimatableScaleValue scale = null;
        AnimatableFloatValue rotation = null;
        AnimatableIntegerValue opacity = null;
        AnimatableFloatValue startOpacity = null;
        AnimatableFloatValue endOpacity = null;
        AnimatableFloatValue skew = null;
        AnimatableFloatValue skewAngle = null;

        boolean isObject = reader.peek() == JsonReader.Token.BEGIN_OBJECT;
        if (isObject) {
            reader.beginObject();
        }
        while (reader.hasNext()) {
            switch (reader.selectName(NAMES)) {
                case 0:
                    reader.beginObject();
                    while (reader.hasNext()) {
                        switch (reader.selectName(ANIMATABLE_NAMES)) {
                            case 0:
                                anchorPoint = AnimatablePathValueParser.parse(reader, composition);
                                break;
                            default:
                                reader.skipName();
                                reader.skipValue();
                        }
                    }
                    reader.endObject();
                    break;
                case 1:
                    position = AnimatablePathValueParser.parseSplitPath(reader, composition);
                    break;
                case 2:
                    scale = AnimatableValueParser.parseScale(reader, composition);
                    break;
                case 3:
                    composition.addWarning("Lottie doesn't support 3D layers.");
                case 4:
                    /**
                     * Sometimes split path rotation gets exported like:
                     *         "rz": {
                     *           "a": 1,
                     *           "k": [
                     *             {}
                     *           ]
                     *         },
                     * which doesn't parse to a real keyframe.
                     */
                    rotation = AnimatableValueParser.parseFloat(reader, composition, false);
                    if (rotation.getKeyframes().isEmpty()) {
                        rotation.getKeyframes()
                            .add(new Keyframe<>(composition, 0f, 0f, null, 0f, composition.getEndFrame()));
                    } else if (rotation.getKeyframes().get(0).startValue == null) {
                        rotation.getKeyframes()
                            .set(0, new Keyframe<>(composition, 0f, 0f, null, 0f, composition.getEndFrame()));
                    }
                    break;
                case 5:
                    opacity = AnimatableValueParser.parseInteger(reader, composition);
                    break;
                case 6:
                    startOpacity = AnimatableValueParser.parseFloat(reader, composition, false);
                    break;
                case 7:
                    endOpacity = AnimatableValueParser.parseFloat(reader, composition, false);
                    break;
                case 8:
                    skew = AnimatableValueParser.parseFloat(reader, composition, false);
                    break;
                case 9:
                    skewAngle = AnimatableValueParser.parseFloat(reader, composition, false);
                    break;
                default:
                    reader.skipName();
                    reader.skipValue();
            }
        }
        if (isObject) {
            reader.endObject();
        }

        if (isAnchorPointIdentity(anchorPoint)) {
            anchorPoint = null;
        }
        if (isPositionIdentity(position)) {
            position = null;
        }
        if (isRotationIdentity(rotation)) {
            rotation = null;
        }
        if (isScaleIdentity(scale)) {
            scale = null;
        }
        if (isSkewIdentity(skew)) {
            skew = null;
        }
        if (isSkewAngleIdentity(skewAngle)) {
            skewAngle = null;
        }
        return new AnimatableTransform(anchorPoint, position, scale, rotation, opacity, startOpacity, endOpacity, skew,
            skewAngle);
    }

    private static boolean isAnchorPointIdentity(AnimatablePathValue anchorPoint) {
        return anchorPoint == null || (anchorPoint.isStatic() && anchorPoint.getKeyframes().get(0).startValue.equals(0f,
            0f));
    }

    private static boolean isPositionIdentity(AnimatableValue<Point, Point> position) {
        return position == null || (!(position instanceof AnimatableSplitDimensionPathValue) && position.isStatic()
            && position.getKeyframes().get(0).startValue.equals(0f, 0f));
    }

    private static boolean isRotationIdentity(AnimatableFloatValue rotation) {
        return rotation == null || (rotation.isStatic() && rotation.getKeyframes().get(0).startValue == 0f);
    }

    private static boolean isScaleIdentity(AnimatableScaleValue scale) {
        return scale == null || (scale.isStatic() && scale.getKeyframes().get(0).startValue.equals(1f, 1f));
    }

    private static boolean isSkewIdentity(AnimatableFloatValue skew) {
        return skew == null || (skew.isStatic() && skew.getKeyframes().get(0).startValue == 0f);
    }

    private static boolean isSkewAngleIdentity(AnimatableFloatValue skewAngle) {
        return skewAngle == null || (skewAngle.isStatic() && skewAngle.getKeyframes().get(0).startValue == 0f);
    }
}
